package org.budo.aliyun.sdk.util;

import java.util.Arrays;
import java.util.Map;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.budo.support.assertion.Assert;
import org.budo.support.java.net.util.UrlEncodeUtil;

/**
 * @author lmw
 */
public class BudoAliyunSdkUtil {
    private final static String H_MAC_SHA1 = "HmacSHA1";

    private static final String ENCODING_UTF8 = "UTF-8";

    private static final String HTTP_METHOD_GET = "GET";

    private static final String SEPARATOR_AND = "&";

    public static byte[] sign(String stringToSign, String accessKeySecret) {
        try {
            String key = accessKeySecret + "&";

            Mac mac = Mac.getInstance(H_MAC_SHA1);
            mac.init(new SecretKeySpec(key.getBytes(ENCODING_UTF8), H_MAC_SHA1));
            byte[] signData = mac.doFinal(stringToSign.toString().getBytes(ENCODING_UTF8));
            return signData;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static String percentEncode(String value) {
        return UrlEncodeUtil.encode(value, ENCODING_UTF8) // 
                .replace("+", "%20")//
                .replace("*", "%2A") // 
                .replace("%7E", "~");
    }

    public static String signature(Map<String, Object> parameters, String accessKeySecret) {
        // 对参数进行排序
        String[] sortedKeys = parameters.keySet().toArray(new String[] {});
        Arrays.sort(sortedKeys);

        // 生成stringToSign字符串
        StringBuilder stringToSign = new StringBuilder();
        stringToSign.append(HTTP_METHOD_GET).append(SEPARATOR_AND);
        stringToSign.append(percentEncode("/")).append(SEPARATOR_AND);

        StringBuilder canonicalizedQueryString = new StringBuilder();
        for (String key : sortedKeys) { // 这里注意对key和value进行编码
            Object value = parameters.get(key);
            Assert.notNull(value, "[#" + key + "] is null");
            String valueString = value.toString();
            canonicalizedQueryString.append("&")
                    .append(percentEncode(key)).append("=")
                    .append(percentEncode(valueString));
        }

        // 这里注意对canonicalizedQueryString进行编码
        stringToSign.append(percentEncode(canonicalizedQueryString.toString().substring(1)));

        byte[] signData = sign(stringToSign.toString(), accessKeySecret);

        return new String(Base64.encodeBase64(signData));
    }
}